This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.
First we are going to install the iAtlas-modules package to gain access to plotting functions.
packages = c("magrittr", "wrapr", "dplyr", "feather", "tidyr")
sapply(packages, function(x) {
if (!require(x,character.only = TRUE))
install.packages(x)
library(x,character.only = TRUE)
})
Loading required package: tidyr
Attaching package: ‘tidyr’
The following objects are masked from ‘package:wrapr’:
pack, unpack
The following object is masked from ‘package:magrittr’:
extract
$magrittr
[1] "iatlas.modules" "feather" "dplyr" "wrapr" "magrittr" "stats"
[7] "graphics" "grDevices" "utils" "datasets" "methods" "base"
$wrapr
[1] "iatlas.modules" "feather" "dplyr" "wrapr" "magrittr" "stats"
[7] "graphics" "grDevices" "utils" "datasets" "methods" "base"
$dplyr
[1] "iatlas.modules" "feather" "dplyr" "wrapr" "magrittr" "stats"
[7] "graphics" "grDevices" "utils" "datasets" "methods" "base"
$feather
[1] "iatlas.modules" "feather" "dplyr" "wrapr" "magrittr" "stats"
[7] "graphics" "grDevices" "utils" "datasets" "methods" "base"
$tidyr
[1] "tidyr" "iatlas.modules" "feather" "dplyr" "wrapr" "magrittr"
[7] "stats" "graphics" "grDevices" "utils" "datasets" "methods"
[13] "base"
# and our iatlas package from github
if (!require(iatlas.modules)) {
devtools::install_github("CRI-iAtlas/iatlas.modules")
library(iatlas.modules)
}
We have a collection of helper functions in the ‘notebook_functions.R’ file.
The main plotting function we’re using here is called ‘plotly_bar’. You can get help with ‘?plotly_bar’.
Here we’ll use source to bring them in.
source('functions/notebook_functions.R')
Tissue compartment fractions barplot
In this case we’ll assume you have leukocyte, stromal, and immune tissue fractions for each sample.
We’ll need a data.frame with the following columns:
Group ## (could be anything, but immune subytpe is a good choice.) fraction_type ## c(leukocyte_fraction, Tumor_fraction, Stromal_fraction) fraction ## a numeric value.
Here’s a example simulation.
df <- data.frame(
GROUP = sample(x=c('C1','C2','C3','C4','C5','C6'), size=100, replace=T),
fraction_type = sample(c('leukocyte_fraction', 'Tumor_fraction', 'Stromal_fraction'), size=100, replace=T),
fraction=rnorm(n=100, mean = 0.5, sd = 0.05)
)
head(df)
The barplot function takes a very specific format, so we’ll transform the data.frame from above using the ‘build_cellcontent_barplot_df2’ function. It essentially gives it a tidy format with generic column names.
barplot_df <- build_cellcontent_barplot_df2( # could use better name
df,
x_column = "fraction_type",
y_column = "fraction",
sort_by_var_choice = "Group",
reorder_func_choice = "None"
)
Now we’re ready to plot. We will use the plot functions from the iatlas.modules package.
Here we’re plotting the mean fraction per group with error bars.
put reorder function here
iatlas.modules::plotly_bar(
plot_data = barplot_df,
x_col = 'x',
y_col = 'y',
error_col = 'error',
color_col = 'color',
ylab = 'Fraction Mean',
xlab = 'Fraction Type by Group',
title = 'Tissue type fractions by group')
Cell content plots
Now, suppose we have cell type contents for each sample with groups, meaning each sample is assigned a group, such as immune subtype.
In the simulation below, we have 6 goups, and a number of aggregated cell types within each group. Then we have a fraction for each cell type, where the sum is ~1.0.
get_fractions <- function(n){
f <- runif(n=6)
f/sum(f)
}
df <- data.frame(
GROUP = unlist(sapply(1:6, function(i) rep_len(paste0('C', as.character(i)), 6), simplify = F)),
fraction_type = rep_len(c('Dendritic_cells', 'Eosinophils', 'Lymphocytes', 'Macrophage', 'Mast_cells', 'Neutrophils'), 6),
fraction=unlist(sapply(1:6, function(i) get_fractions(6), simplify = F))
)
head(df)
The barplot function takes a very specific format, so we’ll transform the data.frame from above using the ‘build_cellcontent_barplot_df2’ function. It essentially gives it a tidy format with generic column names.
barplot_df <- build_cellcontent_barplot_df2( # could use better name
df,
x_column = "fraction_type",
y_column = "fraction",
sort_by_var_choice = "Group",
reorder_func_choice = "None"
)
Now we’re ready to plot. We will use the plot functions from the iatlas.modules package.
put reorder function here
iatlas.modules::plotly_bar(
plot_data = barplot_df,
x_col = 'x',
y_col = 'y',
error_col = NA, ## turning off the error bars
color_col = 'color',
ylab = 'Cell Type Fraction',
xlab = 'Fraction by Group',
title = 'Celltype fractions by group'
)
Plot your results with iAtlas results.
# read in the "feature matrix" (fmx)
iatlas_fmx <- feather::read_feather('data/fmx_df.feather')
iatlas_fmx[1:5, 1:5]
NA
Let us then create a new data.frame that can be merged with the simulated data above. Since we’re grouping the barplots, we want to make sure the iatlas groups have different names compared to your groups… even if they represent fundementaly the same thing (i.e. C2).
# first we'll subset to a single cancer type.
kich_fmx <- iatlas_fmx %>% dplyr::filter(Study == 'KICH')
# then we'll annotate the iatlas labels.
kich_fmx$Subtype_Immune_Model_Based <- sapply(kich_fmx$Subtype_Immune_Model_Based, function(x) paste0('iAtlas_',x))
# Next we work towards formating it in such a way as to bind to the above data.frame
# Above we have cell types:
# 'Dendritic Cells', 'Eosinophils', 'Lymphocytes', 'Macrophages', 'Mast Cells', 'Neutrophils'
kich_fmx2 <- kich_fmx %>%
dplyr::select(Subtype_Immune_Model_Based,
Dendritic_cells.Aggregate1,
Eosinophils.Aggregate1,
Lymphocytes.Aggregate1,
Macrophage.Aggregate1,
Mast_cells.Aggregate1,
Neutrophils.Aggregate1
)
# rename the cell types by removing the 'aggregate1'
colnames(kich_fmx2) <- unlist(sapply(colnames(kich_fmx2), function(x) strsplit(x, '.Aggregate1', fixed=T)))
colnames(kich_fmx2)[1] <- "GROUP"
# and finally we'll go from wide to a narrow matrix
kich_fmx2_long <- tidyr::gather(kich_fmx2, fraction_type, fraction, Dendritic_cells:Neutrophils, factor_key=TRUE)
# merge dfs
new_df <- rbind(df, kich_fmx2_long)
The barplot function takes a very specific format, so we’ll transform the data.frame from above using the ‘build_cellcontent_barplot_df2’ function. It essentially gives it a tidy format with generic column names.
barplot_df <- build_cellcontent_barplot_df2( # could use better name
new_df,
x_column = "fraction_type",
y_column = "fraction",
sort_by_var_choice = "Group", ## Choose a feature to sort on
reorder_func_choice = "None" ## functions include Min, Max, Mean
)
Now we’re ready to plot. We will use the plot functions from the iatlas.modules package. This will sort on group labels.
iatlas.modules::plotly_bar(
plot_data = barplot_df,
x_col = 'x',
y_col = 'y',
error_col = NA, ## turning off the error bars
color_col = 'color',
ylab = 'Cell Type Fraction',
xlab = 'Fraction by Group',
title = 'Celltype fractions by group'
)
Here, we’ll use the reordering function, by selecting one of the cell types (Neutrophils) and a function (Min, Max, Mean).
barplot_df <- build_cellcontent_barplot_df2( # could use better name
new_df,
x_column = "fraction_type",
y_column = "fraction",
sort_by_var_choice = "Neutrophils", ## Choose a feature to sort on
reorder_func_choice = "Max" ## functions include Min, Max, Mean
)
iatlas.modules::plotly_bar(
plot_data = barplot_df,
x_col = 'x',
y_col = 'y',
error_col = NA, ## turning off the error bars
color_col = 'color',
ylab = 'Cell Type Fraction',
xlab = 'Fraction by Group',
title = 'Celltype fractions by group'
)
LS0tCnRpdGxlOiAiQ1JJIGlBdGxhcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ3RybCtTaGlmdCtFbnRlciouIAoKRmlyc3Qgd2UgYXJlIGdvaW5nIHRvIGluc3RhbGwgdGhlIGlBdGxhcy1tb2R1bGVzIHBhY2thZ2UgdG8gZ2FpbiBhY2Nlc3MgdG8gcGxvdHRpbmcgZnVuY3Rpb25zLgoKYGBge3J9CnBhY2thZ2VzID0gYygibWFncml0dHIiLCAid3JhcHIiLCAiZHBseXIiLCAiZmVhdGhlciIsICJ0aWR5ciIpCgpzYXBwbHkocGFja2FnZXMsIGZ1bmN0aW9uKHgpIHsKICBpZiAoIXJlcXVpcmUoeCxjaGFyYWN0ZXIub25seSA9IFRSVUUpKQogICAgaW5zdGFsbC5wYWNrYWdlcyh4KQogICAgbGlicmFyeSh4LGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKfSkKCiMgYW5kIG91ciBpYXRsYXMgcGFja2FnZSBmcm9tIGdpdGh1YgppZiAoIXJlcXVpcmUoaWF0bGFzLm1vZHVsZXMpKSB7CiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJDUkktaUF0bGFzL2lhdGxhcy5tb2R1bGVzIikKICBsaWJyYXJ5KGlhdGxhcy5tb2R1bGVzKQp9CgpgYGAKCldlIGhhdmUgYSBjb2xsZWN0aW9uIG9mIGhlbHBlciBmdW5jdGlvbnMgaW4gdGhlICdub3RlYm9va19mdW5jdGlvbnMuUicgZmlsZS4KClRoZSBtYWluIHBsb3R0aW5nIGZ1bmN0aW9uIHdlJ3JlIHVzaW5nIGhlcmUgaXMgY2FsbGVkICdwbG90bHlfYmFyJy4KWW91IGNhbiBnZXQgaGVscCB3aXRoICc/cGxvdGx5X2JhcicuCgpIZXJlIHdlJ2xsIHVzZSBzb3VyY2UgdG8gYnJpbmcgdGhlbSBpbi4KYGBge3J9CnNvdXJjZSgnZnVuY3Rpb25zL25vdGVib29rX2Z1bmN0aW9ucy5SJykKYGBgCgojIFRpc3N1ZSBjb21wYXJ0bWVudCBmcmFjdGlvbnMgYmFycGxvdAoKSW4gdGhpcyBjYXNlIHdlJ2xsIGFzc3VtZSB5b3UgaGF2ZSBsZXVrb2N5dGUsIHN0cm9tYWwsIGFuZCBpbW11bmUKdGlzc3VlIGZyYWN0aW9ucyBmb3IgZWFjaCBzYW1wbGUuCgpXZSdsbCBuZWVkIGEgZGF0YS5mcmFtZSB3aXRoIHRoZSBmb2xsb3dpbmcgY29sdW1uczoKCkdyb3VwICAgICAgICAgIyMgKGNvdWxkIGJlIGFueXRoaW5nLCBidXQgaW1tdW5lIHN1Ynl0cGUgaXMgYSBnb29kIGNob2ljZS4pCmZyYWN0aW9uX3R5cGUgIyMgYyhsZXVrb2N5dGVfZnJhY3Rpb24sIFR1bW9yX2ZyYWN0aW9uLCBTdHJvbWFsX2ZyYWN0aW9uKQpmcmFjdGlvbiAgICAgICMjIGEgbnVtZXJpYyB2YWx1ZS4KCkhlcmUncyBhIGV4YW1wbGUgc2ltdWxhdGlvbi4KCmBgYHtyfQoKZGYgPC0gZGF0YS5mcmFtZSgKICBHUk9VUCA9IHNhbXBsZSh4PWMoJ0MxJywnQzInLCdDMycsJ0M0JywnQzUnLCdDNicpLCBzaXplPTEwMCwgcmVwbGFjZT1UKSwKICBmcmFjdGlvbl90eXBlID0gc2FtcGxlKGMoJ2xldWtvY3l0ZV9mcmFjdGlvbicsICdUdW1vcl9mcmFjdGlvbicsICdTdHJvbWFsX2ZyYWN0aW9uJyksIHNpemU9MTAwLCByZXBsYWNlPVQpLAogIGZyYWN0aW9uPXJub3JtKG49MTAwLCBtZWFuID0gMC41LCBzZCA9IDAuMDUpCikKCmhlYWQoZGYpCmBgYAoKClRoZSBiYXJwbG90IGZ1bmN0aW9uIHRha2VzIGEgdmVyeSBzcGVjaWZpYyBmb3JtYXQsIHNvIHdlJ2xsIHRyYW5zZm9ybSB0aGUgCmRhdGEuZnJhbWUgZnJvbSBhYm92ZSB1c2luZyB0aGUgJ2J1aWxkX2NlbGxjb250ZW50X2JhcnBsb3RfZGYyJyBmdW5jdGlvbi4KSXQgZXNzZW50aWFsbHkgZ2l2ZXMgaXQgYSB0aWR5IGZvcm1hdCB3aXRoIGdlbmVyaWMgY29sdW1uIG5hbWVzLgoKYGBge3J9CgpiYXJwbG90X2RmIDwtIGJ1aWxkX2NlbGxjb250ZW50X2JhcnBsb3RfZGYyKCAjIGNvdWxkIHVzZSBiZXR0ZXIgbmFtZQogICAgZGYsCiAgICB4X2NvbHVtbiA9ICJmcmFjdGlvbl90eXBlIiwKICAgIHlfY29sdW1uID0gImZyYWN0aW9uIiwKICAgIHNvcnRfYnlfdmFyX2Nob2ljZSA9ICJHcm91cCIsIAogICAgcmVvcmRlcl9mdW5jX2Nob2ljZSA9ICJOb25lIgopCgpgYGAKCk5vdyB3ZSdyZSByZWFkeSB0byBwbG90LiBXZSB3aWxsIHVzZSB0aGUgcGxvdCBmdW5jdGlvbnMgZnJvbSB0aGUgaWF0bGFzLm1vZHVsZXMgCnBhY2thZ2UuCgpIZXJlIHdlJ3JlIHBsb3R0aW5nIHRoZSBtZWFuIGZyYWN0aW9uIHBlciBncm91cCB3aXRoIGVycm9yIGJhcnMuCgojIyBwdXQgcmVvcmRlciBmdW5jdGlvbiBoZXJlICMjCgpgYGB7cn0KaWF0bGFzLm1vZHVsZXM6OnBsb3RseV9iYXIoCiAgcGxvdF9kYXRhID0gYmFycGxvdF9kZiwgCiAgeF9jb2wgPSAneCcsIAogIHlfY29sID0gJ3knLCAKICBlcnJvcl9jb2wgPSAnZXJyb3InLCAKICBjb2xvcl9jb2wgPSAnY29sb3InLCAKICB5bGFiID0gJ0ZyYWN0aW9uIE1lYW4nLCAKICB4bGFiID0gJ0ZyYWN0aW9uIFR5cGUgYnkgR3JvdXAnLAogIHRpdGxlID0gJ1Rpc3N1ZSB0eXBlIGZyYWN0aW9ucyBieSBncm91cCcpCmBgYAoKCiMgQ2VsbCBjb250ZW50IHBsb3RzCgpOb3csIHN1cHBvc2Ugd2UgaGF2ZSBjZWxsIHR5cGUgY29udGVudHMgZm9yIGVhY2ggc2FtcGxlIHdpdGggZ3JvdXBzLCBtZWFuaW5nIGVhY2gKc2FtcGxlIGlzIGFzc2lnbmVkIGEgZ3JvdXAsIHN1Y2ggYXMgaW1tdW5lIHN1YnR5cGUuIAoKSW4gdGhlIHNpbXVsYXRpb24gYmVsb3csIHdlIGhhdmUgNiBnb3VwcywgYW5kIGEgbnVtYmVyIG9mIGFnZ3JlZ2F0ZWQgY2VsbCB0eXBlcyAKd2l0aGluIGVhY2ggZ3JvdXAuICBUaGVuIHdlIGhhdmUgYSBmcmFjdGlvbiBmb3IgZWFjaCBjZWxsIHR5cGUsIHdoZXJlIHRoZSBzdW0KaXMgfjEuMC4KCmBgYHtyfQoKZ2V0X2ZyYWN0aW9ucyA8LSBmdW5jdGlvbihuKXsKICBmIDwtIHJ1bmlmKG49NikKICBmL3N1bShmKQp9CgpkZiA8LSBkYXRhLmZyYW1lKAogIEdST1VQID0gdW5saXN0KHNhcHBseSgxOjYsIGZ1bmN0aW9uKGkpIHJlcF9sZW4ocGFzdGUwKCdDJywgYXMuY2hhcmFjdGVyKGkpKSwgNiksIHNpbXBsaWZ5ID0gRikpLAogIGZyYWN0aW9uX3R5cGUgPSByZXBfbGVuKGMoJ0RlbmRyaXRpY19jZWxscycsICdFb3Npbm9waGlscycsICdMeW1waG9jeXRlcycsICdNYWNyb3BoYWdlJywgJ01hc3RfY2VsbHMnLCAnTmV1dHJvcGhpbHMnKSwgNiksCiAgZnJhY3Rpb249dW5saXN0KHNhcHBseSgxOjYsIGZ1bmN0aW9uKGkpIGdldF9mcmFjdGlvbnMoNiksIHNpbXBsaWZ5ID0gRikpCikKCmhlYWQoZGYpCmBgYAoKCgpUaGUgYmFycGxvdCBmdW5jdGlvbiB0YWtlcyBhIHZlcnkgc3BlY2lmaWMgZm9ybWF0LCBzbyB3ZSdsbCB0cmFuc2Zvcm0gdGhlIApkYXRhLmZyYW1lIGZyb20gYWJvdmUgdXNpbmcgdGhlICdidWlsZF9jZWxsY29udGVudF9iYXJwbG90X2RmMicgZnVuY3Rpb24uCkl0IGVzc2VudGlhbGx5IGdpdmVzIGl0IGEgdGlkeSBmb3JtYXQgd2l0aCBnZW5lcmljIGNvbHVtbiBuYW1lcy4KCmBgYHtyfQoKYmFycGxvdF9kZiA8LSBidWlsZF9jZWxsY29udGVudF9iYXJwbG90X2RmMiggIyBjb3VsZCB1c2UgYmV0dGVyIG5hbWUKICAgIGRmLAogICAgeF9jb2x1bW4gPSAiZnJhY3Rpb25fdHlwZSIsCiAgICB5X2NvbHVtbiA9ICJmcmFjdGlvbiIsCiAgICBzb3J0X2J5X3Zhcl9jaG9pY2UgPSAiR3JvdXAiLCAKICAgIHJlb3JkZXJfZnVuY19jaG9pY2UgPSAiTm9uZSIKKQoKYGBgCgpOb3cgd2UncmUgcmVhZHkgdG8gcGxvdC4gV2Ugd2lsbCB1c2UgdGhlIHBsb3QgZnVuY3Rpb25zIGZyb20gdGhlIGlhdGxhcy5tb2R1bGVzIApwYWNrYWdlLgoKIyMgcHV0IHJlb3JkZXIgZnVuY3Rpb24gaGVyZSAjIwoKYGBge3J9CmlhdGxhcy5tb2R1bGVzOjpwbG90bHlfYmFyKAogIHBsb3RfZGF0YSA9IGJhcnBsb3RfZGYsIAogIHhfY29sID0gJ3gnLCAKICB5X2NvbCA9ICd5JywgCiAgZXJyb3JfY29sID0gTkEsICMjIHR1cm5pbmcgb2ZmIHRoZSBlcnJvciBiYXJzCiAgY29sb3JfY29sID0gJ2NvbG9yJywgCiAgeWxhYiA9ICdDZWxsIFR5cGUgRnJhY3Rpb24nLCAKICB4bGFiID0gJ0ZyYWN0aW9uIGJ5IEdyb3VwJywKICB0aXRsZSA9ICdDZWxsdHlwZSBmcmFjdGlvbnMgYnkgZ3JvdXAnCikKYGBgCgoKIyBQbG90IHlvdXIgcmVzdWx0cyB3aXRoIGlBdGxhcyByZXN1bHRzLgoKYGBge3J9CgojIHJlYWQgaW4gdGhlICJmZWF0dXJlIG1hdHJpeCIgKGZteCkKaWF0bGFzX2ZteCA8LSBmZWF0aGVyOjpyZWFkX2ZlYXRoZXIoJ2RhdGEvZm14X2RmLmZlYXRoZXInKQppYXRsYXNfZm14WzE6NSwgMTo1XQoKYGBgCgpMZXQgdXMgdGhlbiBjcmVhdGUgYSBuZXcgZGF0YS5mcmFtZSB0aGF0IGNhbiBiZSBtZXJnZWQgd2l0aCB0aGUgc2ltdWxhdGVkIGRhdGEgYWJvdmUuClNpbmNlIHdlJ3JlIGdyb3VwaW5nIHRoZSBiYXJwbG90cywgd2Ugd2FudCB0byBtYWtlIHN1cmUgdGhlIGlhdGxhcyBncm91cHMgaGF2ZQpkaWZmZXJlbnQgbmFtZXMgY29tcGFyZWQgdG8geW91ciBncm91cHMuLi4gZXZlbiBpZiB0aGV5IHJlcHJlc2VudCBmdW5kZW1lbnRhbHkKdGhlIHNhbWUgdGhpbmcgKGkuZS4gQzIpLgoKYGBge3J9CgojIGZpcnN0IHdlJ2xsIHN1YnNldCB0byBhIHNpbmdsZSBjYW5jZXIgdHlwZS4Ka2ljaF9mbXggPC0gaWF0bGFzX2ZteCAlPiUgZHBseXI6OmZpbHRlcihTdHVkeSA9PSAnS0lDSCcpCgojIHRoZW4gd2UnbGwgYW5ub3RhdGUgdGhlIGlhdGxhcyBsYWJlbHMuCmtpY2hfZm14JFN1YnR5cGVfSW1tdW5lX01vZGVsX0Jhc2VkIDwtIHNhcHBseShraWNoX2ZteCRTdWJ0eXBlX0ltbXVuZV9Nb2RlbF9CYXNlZCwgZnVuY3Rpb24oeCkgcGFzdGUwKCdpQXRsYXNfJyx4KSkKCiMgTmV4dCB3ZSB3b3JrIHRvd2FyZHMgZm9ybWF0aW5nIGl0IGluIHN1Y2ggYSB3YXkgYXMgdG8gYmluZCB0byB0aGUgYWJvdmUgZGF0YS5mcmFtZQojIEFib3ZlIHdlIGhhdmUgY2VsbCB0eXBlczoKIyAnRGVuZHJpdGljIENlbGxzJywgJ0Vvc2lub3BoaWxzJywgJ0x5bXBob2N5dGVzJywgJ01hY3JvcGhhZ2VzJywgJ01hc3QgQ2VsbHMnLCAnTmV1dHJvcGhpbHMnCmtpY2hfZm14MiA8LSBraWNoX2ZteCAlPiUgCiAgZHBseXI6OnNlbGVjdChTdWJ0eXBlX0ltbXVuZV9Nb2RlbF9CYXNlZCwgCiAgICAgICAgICAgICAgICAgRGVuZHJpdGljX2NlbGxzLkFnZ3JlZ2F0ZTEsCiAgICAgICAgICAgICAgICAgRW9zaW5vcGhpbHMuQWdncmVnYXRlMSwKICAgICAgICAgICAgICAgICBMeW1waG9jeXRlcy5BZ2dyZWdhdGUxLAogICAgICAgICAgICAgICAgIE1hY3JvcGhhZ2UuQWdncmVnYXRlMSwKICAgICAgICAgICAgICAgICBNYXN0X2NlbGxzLkFnZ3JlZ2F0ZTEsCiAgICAgICAgICAgICAgICAgTmV1dHJvcGhpbHMuQWdncmVnYXRlMQogICAgICAgICAgICAgICAgICkKCiMgcmVuYW1lIHRoZSBjZWxsIHR5cGVzIGJ5IHJlbW92aW5nIHRoZSAnYWdncmVnYXRlMScKY29sbmFtZXMoa2ljaF9mbXgyKSA8LSB1bmxpc3Qoc2FwcGx5KGNvbG5hbWVzKGtpY2hfZm14MiksIGZ1bmN0aW9uKHgpIHN0cnNwbGl0KHgsICcuQWdncmVnYXRlMScsIGZpeGVkPVQpKSkKY29sbmFtZXMoa2ljaF9mbXgyKVsxXSA8LSAiR1JPVVAiCgojIGFuZCBmaW5hbGx5IHdlJ2xsIGdvIGZyb20gd2lkZSB0byBhIG5hcnJvdyBtYXRyaXgKa2ljaF9mbXgyX2xvbmcgPC0gdGlkeXI6OmdhdGhlcihraWNoX2ZteDIsIGZyYWN0aW9uX3R5cGUsIGZyYWN0aW9uLCBEZW5kcml0aWNfY2VsbHM6TmV1dHJvcGhpbHMsIGZhY3Rvcl9rZXk9VFJVRSkKCiMgbWVyZ2UgZGZzCm5ld19kZiA8LSByYmluZChkZiwga2ljaF9mbXgyX2xvbmcpCgpgYGAKCgoKClRoZSBiYXJwbG90IGZ1bmN0aW9uIHRha2VzIGEgdmVyeSBzcGVjaWZpYyBmb3JtYXQsIHNvIHdlJ2xsIHRyYW5zZm9ybSB0aGUgCmRhdGEuZnJhbWUgZnJvbSBhYm92ZSB1c2luZyB0aGUgJ2J1aWxkX2NlbGxjb250ZW50X2JhcnBsb3RfZGYyJyBmdW5jdGlvbi4KSXQgZXNzZW50aWFsbHkgZ2l2ZXMgaXQgYSB0aWR5IGZvcm1hdCB3aXRoIGdlbmVyaWMgY29sdW1uIG5hbWVzLgoKYGBge3J9CgpiYXJwbG90X2RmIDwtIGJ1aWxkX2NlbGxjb250ZW50X2JhcnBsb3RfZGYyKCAjIGNvdWxkIHVzZSBiZXR0ZXIgbmFtZQogICAgbmV3X2RmLAogICAgeF9jb2x1bW4gPSAiZnJhY3Rpb25fdHlwZSIsCiAgICB5X2NvbHVtbiA9ICJmcmFjdGlvbiIsCiAgICBzb3J0X2J5X3Zhcl9jaG9pY2UgPSAiR3JvdXAiLCAgICMjIENob29zZSBhIGZlYXR1cmUgdG8gc29ydCBvbgogICAgcmVvcmRlcl9mdW5jX2Nob2ljZSA9ICJOb25lIiAgICAgICAgICAgIyMgZnVuY3Rpb25zIGluY2x1ZGUgTWluLCBNYXgsIE1lYW4KKQoKYGBgCgpOb3cgd2UncmUgcmVhZHkgdG8gcGxvdC4gV2Ugd2lsbCB1c2UgdGhlIHBsb3QgZnVuY3Rpb25zIGZyb20gdGhlIGlhdGxhcy5tb2R1bGVzIApwYWNrYWdlLiAgVGhpcyB3aWxsIHNvcnQgb24gZ3JvdXAgbGFiZWxzLgoKYGBge3J9CmlhdGxhcy5tb2R1bGVzOjpwbG90bHlfYmFyKAogIHBsb3RfZGF0YSA9IGJhcnBsb3RfZGYsIAogIHhfY29sID0gJ3gnLCAKICB5X2NvbCA9ICd5JywgCiAgZXJyb3JfY29sID0gTkEsICMjIHR1cm5pbmcgb2ZmIHRoZSBlcnJvciBiYXJzCiAgY29sb3JfY29sID0gJ2NvbG9yJywgCiAgeWxhYiA9ICdDZWxsIFR5cGUgRnJhY3Rpb24nLCAKICB4bGFiID0gJ0ZyYWN0aW9uIGJ5IEdyb3VwJywKICB0aXRsZSA9ICdDZWxsdHlwZSBmcmFjdGlvbnMgYnkgZ3JvdXAnCikKYGBgCgoKCkhlcmUsIHdlJ2xsIHVzZSB0aGUgcmVvcmRlcmluZyBmdW5jdGlvbiwgYnkgc2VsZWN0aW5nIG9uZSBvZiB0aGUgY2VsbCB0eXBlcwooTmV1dHJvcGhpbHMpIGFuZCBhIGZ1bmN0aW9uIChNaW4sIE1heCwgTWVhbikuCgoKYGBge3J9CgpiYXJwbG90X2RmIDwtIGJ1aWxkX2NlbGxjb250ZW50X2JhcnBsb3RfZGYyKCAjIGNvdWxkIHVzZSBiZXR0ZXIgbmFtZQogICAgbmV3X2RmLAogICAgeF9jb2x1bW4gPSAiZnJhY3Rpb25fdHlwZSIsCiAgICB5X2NvbHVtbiA9ICJmcmFjdGlvbiIsCiAgICBzb3J0X2J5X3Zhcl9jaG9pY2UgPSAiTmV1dHJvcGhpbHMiLCAgICMjIENob29zZSBhIGZlYXR1cmUgdG8gc29ydCBvbgogICAgcmVvcmRlcl9mdW5jX2Nob2ljZSA9ICJNYXgiICAgICAgICAgICAjIyBmdW5jdGlvbnMgaW5jbHVkZSBNaW4sIE1heCwgTWVhbgopCgppYXRsYXMubW9kdWxlczo6cGxvdGx5X2JhcigKICBwbG90X2RhdGEgPSBiYXJwbG90X2RmLCAKICB4X2NvbCA9ICd4JywgCiAgeV9jb2wgPSAneScsIAogIGVycm9yX2NvbCA9IE5BLCAjIyB0dXJuaW5nIG9mZiB0aGUgZXJyb3IgYmFycwogIGNvbG9yX2NvbCA9ICdjb2xvcicsIAogIHlsYWIgPSAnQ2VsbCBUeXBlIEZyYWN0aW9uJywgCiAgeGxhYiA9ICdGcmFjdGlvbiBieSBHcm91cCcsCiAgdGl0bGUgPSAnQ2VsbHR5cGUgZnJhY3Rpb25zIGJ5IGdyb3VwJwopCmBgYAoKCg==